package sk.stuba.fiit.ltasys.web.mvc.model.service.impl;

import java.io.ByteArrayInputStream;

import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;

import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.tsp.TSPAlgorithms;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import sk.stuba.fiit.ltasys.web.mvc.model.service.CommunicatorService;
import sk.stuba.fiit.ltasys.ws.client.CRLServiceClient;
import sk.stuba.fiit.ltasys.ws.client.CertificateServiceClient;
import sk.stuba.fiit.ltasys.ws.client.OcspServiceClient;
import sk.stuba.fiit.ltasys.ws.client.TimestampServiceClient;
import sk.stuba.fiit.pki.ws.schema.beans.CertificateRequest;
import sk.stuba.fiit.pki.ws.schema.beans.CertificateResponse;
import sk.stuba.fiit.pki.ws.schema.beans.CertificateType;
import sk.stuba.fiit.pki.ws.schema.beans.CrlRequest;
import sk.stuba.fiit.pki.ws.schema.beans.CrlResponse;
import sk.stuba.fiit.pki.ws.schema.beans.OcspReqType;
import sk.stuba.fiit.pki.ws.schema.beans.OcspRequest;
import sk.stuba.fiit.pki.ws.schema.beans.OcspResponse;
import sk.stuba.fiit.pki.ws.schema.beans.TimestampRequest;
import sk.stuba.fiit.pki.ws.schema.beans.TimestampResponse;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.x509.X509CRLImpl;

@Service("communicatorService")
public class CommunicatorServiceImpl implements CommunicatorService{

	@Autowired
	private CertificateServiceClient certificateServiceClient;
	
	@Autowired
	private CRLServiceClient crlServiceClient;
	
	@Autowired
	private OcspServiceClient ocspServiceClient;
	
	@Autowired
	private TimestampServiceClient timestampServiceClient;
	
	public X509Certificate getCertificateFromPKIBySerialNumAndIssuer(String serialNumber,String issuer) throws Exception{
			CertificateRequest request = new CertificateRequest();
			CertificateType value = new CertificateType();
			value.setSerialNumber(serialNumber);
			value.setIssuer(issuer);
			request.setCertificatereq(value);
			CertificateResponse resp = certificateServiceClient.getCertificateBySerialNumber(request);
			
			BASE64Decoder decoder = new BASE64Decoder();	
			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
			InputStream in = new ByteArrayInputStream(decoder.decodeBuffer(resp.getCertificateresp().get(0)));		
			X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);
			
			return certificate;
	}
	
	public X509CRL getCRLFromPKIByIssuer(String issuer) throws Exception{
		CrlRequest crlRequest = new CrlRequest();
		crlRequest.withCrlreq(issuer);
    	CrlResponse crlResp = crlServiceClient.getActualCrl(crlRequest);
    	
    	BASE64Decoder decoder = new BASE64Decoder();
    	InputStream in = new ByteArrayInputStream(decoder.decodeBuffer(crlResp.getCrlresp().get(0)));	
    	X509CRL crl = new X509CRLImpl(in);
    	return crl;   	
	}
	
	public OcspResponse getocspFromPKIBySerialAndIssuer(String issuer, String serialNum){
		 OcspRequest ocspReques = new OcspRequest();
    	 OcspReqType ocsprt = new OcspReqType();
    	 ocsprt.setIssuer(issuer);
    	 ocsprt.setSerialNumber(serialNum);
    	 ocspReques.setOcspreq(ocsprt);
    	 OcspResponse ocspresp = ocspServiceClient.getOCSForCertificate(ocspReques);
		return ocspresp;
		
	}
	
	
	// uz poslem hash ktory chcem opeciatkovat 
	public TimeStampResponse getTimestamp(byte[] data) throws Exception{
		TimeStampRequestGenerator generator = new TimeStampRequestGenerator();
		ASN1ObjectIdentifier asn1objectidentifier = TSPAlgorithms.SHA1;		
		BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());		
		TimeStampRequest timestamprequest =  generator.generate(asn1objectidentifier, data, nonce);		
		
		BASE64Encoder encoder = new BASE64Encoder();
		Collection<String> reqString = new ArrayList<String>(3);
		reqString.add(encoder.encodeBuffer(timestamprequest.getEncoded()));
			
		TimestampRequest tsreq = new TimestampRequest();		
		tsreq.withTimestamreq(reqString);
		
		TimestampResponse tsresp = timestampServiceClient.getTimeStamp(tsreq);
		BASE64Decoder decoder = new BASE64Decoder();
    	InputStream in = new ByteArrayInputStream(decoder.decodeBuffer(tsresp.getTimestamresp().get(0)));	
		TimeStampResponse result = new TimeStampResponse(in);
		return result;
	}
}
